﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using CarolLib.WinService;
using CarolLib.Core.Helper;
using DCS.Business.Interface;
using DCS.Business.Manager;
using DCS.Business.Model;
using DCS.BusinessObject.ESB;
using DCS.DataProvider;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using MessagerSync;

namespace DCS.BusinessObject
{
    public class Syncer : SyncerBase
    {

        #region implete abstract method

        /// <summary>
        /// 调webservice
        /// </summary>
        /// <param name="esbparam"></param>
        /// <param name="esbheader"></param>
        public override void CallESBWS(object esbparam, MessagerSync.SoapHeadInfo esbheader)
        {
            ESBTMPPPRLService service = new ESBTMPPPRLService();
            service.RequestEncoding = Encoding.UTF8;
            service.SoapVersion = System.Web.Services.Protocols.SoapProtocolVersion.Soap11;
            service.ESBHeader = ConvertHelper.ConvertObject<ESBHeadInfo, SoapHeadInfo>(esbheader);

            //ESBTMPPPRLService1 s = (ESBTMPPPRLService1)esbparam;
            ESBTMPPPRLServiceResponse response = service.CallESBTMPPPRLService((ESBTMPPPRLService1)esbparam);
        }

        /// <summary>
        /// 构造soap参数
        /// </summary>
        /// <param name="group"></param>
        /// <param name="messagerList"></param>
        /// <param name="flightOnly"></param>
        /// <returns></returns>
        public override object GetESBParam(DCSFileGroup group, MessageGroup messagerList, bool flightOnly)
        {
            ESBTMPPPRLService1 result = new ESBTMPPPRLService1() { PRLMessage = new PRLMessage_Type() };

            Flight_Type flight = new Flight_Type();

            flight.DepartureDate = group.DeptDate;
            flight.FNPostfix = string.Empty;
            flight.DepartureAirport = group.DeptAirport;
            // Lance add the following code to fix the FlightNumber and FNPostfix issue.
            int tempint;
            if (int.TryParse(group.FlightNo, out tempint))
            {
                flight.FlightNumber = group.Carrier + group.FlightNo;
                flight.FNPostfix = string.Empty;
            }
            else
            {
                flight.FlightNumber = group.Carrier + group.FlightNo.Substring(0, group.FlightNo.Length - 1);
                flight.FNPostfix = group.FlightNo.Replace(group.FlightNo.Substring(0, group.FlightNo.Length - 1), string.Empty);
            }

            result.PRLMessage.Flight = flight;

            var prls = GetRelatedPRLs(group, messagerList.PRLList);

            if (!flightOnly)
            {
                try
                {
                    result.PRLMessage.PRLData = GetPRLData(prls);
                }
                catch (Exception ex)
                {
                    Logger.WarnFormat("Error GetPRLData " + group.GroupName, ex);
                    throw ex;
                }

                //lance add.
                if (result.PRLMessage.PRLData.Count() == 0)
                {
                    result.PRLMessage.PRLData = null;
                }
            }
            else
            {
                result.PRLMessage.PRLData = null;
            }
            return result;
        }
        #endregion

        #region private method
        private List<PRLMessage> GetRelatedPRLs(DCSFileGroup group, List<PRLMessage> prlList)
        {
            List<int> ids = group.Select(d => d.FileId).ToList();
            List<PRLMessage> prls = prlList.Where(p => ids.Contains(p.RefFileId)).ToList();
            return prls;
        }
        private readonly Regex RegCKIN = new Regex(@"\w*@M([0-9-]+)\w*");
        private CategoryBySegmentAndCarbin_Type[] GetPRLData(List<PRLMessage> prls)
        {
            IEnumerable<IGrouping<string, PRLMessage>> prlFlightCabinNoGroups = prls.GroupBy(p => p.CabinNo);
            List<CategoryBySegmentAndCarbin_Type> categories = new List<CategoryBySegmentAndCarbin_Type>();

            #region Categories

            foreach (IGrouping<string, PRLMessage> prlFlightCabinNoGroup in prlFlightCabinNoGroups)
            {
                CategoryBySegmentAndCarbin_Type category = new CategoryBySegmentAndCarbin_Type();
                categories.Add(category);

                #region Build Passenger_Type[]

                ICollection<Passenger_Type> passengers = new List<Passenger_Type>();

                foreach (PRLMessage prl in prlFlightCabinNoGroup)
                {
                    Passenger_Type passenger = new Passenger_Type();
                    passengers.Add(passenger);

                    #region BaggageInfo_Type

                    BaggageInfo_Type baggage = new BaggageInfo_Type();
                    passenger.BaggageInfo = baggage;
                    int r;
                    baggage.BaggagePieces = string.IsNullOrEmpty(prl.WK) ? 0 : (int.TryParse(prl.WK.Split('/')[1], out r) ? r : 0);
                    baggage.BaggageWeight = string.IsNullOrEmpty(prl.WK) ? 0 : (int.TryParse(prl.WK.Split('/')[2], out r) ? r : 0);
                    baggage.WeightUnit = "K";

                    #endregion

                    #region BaggageNumberInfo_Type

                    string[] packages = (prl.Package ?? "").Trim().Split(new char[] { '\x20' }, StringSplitOptions.RemoveEmptyEntries);
                    passenger.BaggageNumberInfo = packages.Select(package =>
                    {
                        var packageSplit = package.Split('/');
                        BaggageNumberInfo_Type baggageNumber = new BaggageNumberInfo_Type();
                        baggageNumber.BaggageNumber = packageSplit[0];
                        baggageNumber.TargetCity = packageSplit.Length > 1 ? packageSplit[1] : "";
                        return baggageNumber;
                    }).ToArray();

                    #endregion

                    #region ConnectingFlight_Type

                    string[] outBounds = (prl.OutBound ?? "").Trim().Split(new char[] { '\x20' }, StringSplitOptions.RemoveEmptyEntries);
                    Regex regex = new Regex(@"^(\w{2,3}\d{3,4})([A-Z])(\d{2})([A-Z]{3})$");
                    passenger.ConnectingFlight = outBounds.Select(outBound => new ConnectingFlight_Type()
                    {
                        FlightNumber = regex.Match(outBound).Groups[1].Value,
                        //FNPostfix = regex.Match(outBound).Groups[2].Value,
                        DepartureDate =
                                new DateTime(DateTime.Now.Year, DateTime.Now.Month
                            , (int.TryParse(regex.Match(outBound).Groups[3].Value, out r) ? r : 0)),
                        ArriveAirport = regex.Match(outBound).Groups[4].Value,
                    }).ToArray();

                    #endregion

                    #region FOID_Type

                   // Regex foidRegex = new Regex(@"^([A-Z]{2,})(\d{1,}X{0,1})$");

                    Regex foidRegex = new Regex(@"^([A-Z]{2})(\S*)$");

                    Regex ChinaIDRgx = new Regex(@"^\d{1,}X{0,1}$");

                    GroupCollection foidGroups = foidRegex.Match(prl.FOID ?? "").Groups;
                    Match mhChina = ChinaIDRgx.Match(foidGroups[2].Value);
                    passenger.FOID = new FOID_Type()
                    {

                        //RegistrationType = foidGroups.Count > 1 ? foidGroups[1].Value : "",
                        //RegistrationNumber = foidGroups.Count > 1 ? foidGroups[2].Value : "",

                        RegistrationType = mhChina.Success ? "CHN" : "",
                        RegistrationNumber = foidGroups.Count > 1 ? foidGroups[2].Value : "",
                    };

                    #endregion

                    #region FFPCard_Types

                    Regex fqtRegex = new Regex(@"^([A-Z]+)\x20(\d+)\/([A-Z])$");
                    FFPCard_Type ffpcardFQTU;
                    if (string.IsNullOrEmpty(prl.FQTU))
                        ffpcardFQTU = new FFPCard_Type()
                        {
                            CardLevel = string.Empty,
                            FFPProgramOwner = string.Empty,
                            LoyaltyCardNO = string.Empty,
                        };
                    else
                    {
                        ffpcardFQTU = new FFPCard_Type();
                        ffpcardFQTU.FFPProgramOwner = fqtRegex.Match(prl.FQTU).Groups[1].Value;
                        ffpcardFQTU.LoyaltyCardNO = fqtRegex.Match(prl.FQTU).Groups[2].Value;
                        ffpcardFQTU.CardLevel = fqtRegex.Match(prl.FQTU).Groups[3].Value;
                    }
                    passenger.FrequentFlyerPartneredAirline = ffpcardFQTU;

                    FFPCard_Type ffpcardFQTV;
                    if (string.IsNullOrEmpty(prl.FQTV))
                        ffpcardFQTV = new FFPCard_Type()
                        {
                            CardLevel = string.Empty,
                            FFPProgramOwner = string.Empty,
                            LoyaltyCardNO = string.Empty,
                        };
                    else
                    {
                        ffpcardFQTV = new FFPCard_Type();
                        ffpcardFQTV.FFPProgramOwner = fqtRegex.Match(prl.FQTV).Groups[1].Value;
                        ffpcardFQTV.LoyaltyCardNO = fqtRegex.Match(prl.FQTV).Groups[2].Value;
                        ffpcardFQTV.CardLevel = fqtRegex.Match(prl.FQTV).Groups[3].Value;
                    }
                    passenger.FrequentFlyer = ffpcardFQTV;

                    FFPCard_Type ffpcardFQTR;
                    if (string.IsNullOrEmpty(prl.FQTR))
                        ffpcardFQTR = new FFPCard_Type()
                        {
                            CardLevel = string.Empty,
                            FFPProgramOwner = string.Empty,
                            LoyaltyCardNO = string.Empty,
                        };
                    else
                    {
                        ffpcardFQTR = new FFPCard_Type();
                        ffpcardFQTR.FFPProgramOwner = fqtRegex.Match(prl.FQTR).Groups[1].Value;
                        ffpcardFQTR.LoyaltyCardNO = fqtRegex.Match(prl.FQTR).Groups[2].Value;
                        ffpcardFQTR.CardLevel = fqtRegex.Match(prl.FQTR).Groups[3].Value;
                    }
                    passenger.FrequentFlyerRedemption = ffpcardFQTR;

                    FFPCard_Type ffpcardFQTS;
                    if (string.IsNullOrEmpty(prl.FQTS))
                        ffpcardFQTS = new FFPCard_Type()
                        {
                            CardLevel = string.Empty,
                            FFPProgramOwner = string.Empty,
                            LoyaltyCardNO = string.Empty,
                        };
                    else
                    {
                        ffpcardFQTS = new FFPCard_Type();
                        ffpcardFQTS.FFPProgramOwner = fqtRegex.Match(prl.FQTS).Groups[1].Value;
                        ffpcardFQTS.LoyaltyCardNO = fqtRegex.Match(prl.FQTS).Groups[2].Value;
                        ffpcardFQTS.CardLevel = fqtRegex.Match(prl.FQTS).Groups[3].Value;
                    }
                    passenger.FrequentFlyerUpgrade = ffpcardFQTS;

                    #endregion

                    #region FullName_Type

                    string fullName = "";

                    if (!string.IsNullOrEmpty(prl.PName))
                    {
                        fullName = prl.PName.Trim();
                        if (fullName.EndsWith("MS") || fullName.EndsWith("MR"))
                        {
                            fullName = fullName.Substring(0, fullName.Length - 2);
                        }
                        if (fullName.EndsWith("MRS") || fullName.EndsWith("CHD") || fullName.EndsWith("VIP"))
                        {
                            fullName = fullName.Substring(0, fullName.Length - 3);
                        }
                    }
                    passenger.FullName = fullName=="" ? new FullName_Type()
                    {
                        FullName = string.Empty,
                        GivenName = string.Empty,
                        Surname = string.Empty,
                    }
                        : new FullName_Type()
                    {

                        FullName = fullName,
                        GivenName = fullName.IndexOf('/') != -1 ? fullName.Split('/')[1] : string.Empty,
                        Surname = fullName.IndexOf('/') != -1 ? fullName.Split('/')[0] : string.Empty,
                    };

                    #endregion

                    #region Passport_Type

                    Regex psptRegex = new Regex(@"^HK1\x20(\w+)/([A-Z]+)\/(\w+)/([A-Z]+)(-[A-Z]+)?$");
                    passenger.Passport = prl.PSPT == null ? new Passport_Type()
                    {
                        Birthday = string.Empty,
                        Country = string.Empty,
                        Name = string.Empty,
                        PassportNumber = string.Empty,
                        Sex = string.Empty,
                    }
                    : new Passport_Type()
                    {
                        PassportNumber = psptRegex.Match(prl.PSPT).Groups[1].Value,
                        Country = psptRegex.Match(prl.PSPT).Groups[2].Value,
                        Birthday = psptRegex.Match(prl.PSPT).Groups[3].Value,
                        Sex = psptRegex.Match(prl.PSPT).Groups[4].Value,
                        Name = prl.PName,
                    };

                    #endregion

                    #region SharedFlightInfo_Type

                    Regex shareRegex = new Regex(@"^(\w{2,3}\d{4})([A-Z])(\d{2})([A-Z]{3})(([A-Z]{3})(\d{4})([A-Z]{2})?)?$");
                    passenger.SharedFlightInfo = (prl.ShareCode ?? "").Trim().Split(new char[] { '\x20' }, StringSplitOptions.RemoveEmptyEntries)
                        .Select(shareCode =>
                        {
                            GroupCollection groups = shareRegex.Match(shareCode).Groups;
                            if (groups.Count < 2)
                                return null;
                            SharedFlightInfo_Type shareFlight = new SharedFlightInfo_Type();
                            shareFlight.SharedFlightNumber = groups[1].Value;
                            //FNPostfix = shareRegex.Match(shareCode).Groups[2].Value,
                            shareFlight.SubCarbin = groups[2].Value;
                            shareFlight.Day = new DateTime(DateTime.Now.Year, DateTime.Now.Month,
                                int.TryParse(groups[3].Value.Substring(0, 2), out r) ? r : 0
                                    );
                            shareFlight.DepartureAirport = groups[4].Value;
                            if (groups.Count > 5)
                            {
                                shareFlight.ArriveAirport = groups[6].Value;
                                shareFlight.DepartureTime = shareFlight.Day
                                    .AddHours(int.TryParse(groups[7].Value.Substring(0, 2), out r) ? r : 0)
                                    .AddMinutes(int.TryParse(groups[7].Value.Substring(2, 2), out r) ? r : 0).ToString("hh:mm:ss");
                                //shareFlight.DepartureTime = int.Parse(groups[7].Value.Substring(0, 2)) + ":"
                                //    + int.Parse(groups[7].Value.Substring(2, 2)) + ":00";
                            }
                            return shareFlight;
                        }).ToArray();

                    #endregion

                    #region Direct Use

                    passenger.BoardingCheckNumber = prl.BN;
                    passenger.BoardingGateNumber = prl.GATE;
                    passenger.ChineseName = prl.CNIN;
                    
                    //modify at 2011-9-2 by wuzhongqi/截取字符串中的旅客手机号发送过去

                    passenger.CKIN = string.IsNullOrEmpty(prl.CKIN) ? "" : RegCKIN.Match(prl.CKIN).Groups[1].Value;
                    //

                    passenger.HistoryCabin = prl.HC;
                    passenger.PNRReference = prl.PNR;
                    passenger.PreferredTitle = "";
                    passenger.PSM = prl.PSM;
                    passenger.SeatNumber = prl.Seat;
                    passenger.TicketNumber = prl.TKNE.Split(' ');
                    passenger.SpecialMeal = prl.SPML == SPMLType.None ? "" : prl.SPML.ToString();

                    #endregion

                    #region SSR Flags

                    passenger.STCRIndicator = ((prl.SSR & SSRType.STCR) == SSRType.STCR) ? Passenger_TypeSTCRIndicator.Item1 : 0;
                    passenger.VIPIndicator = prl.IsVip ? Passenger_TypeVIPIndicator.Item1 : 0;
                    passenger.BLNDIndicator = ((prl.SSR & SSRType.BLIND) == SSRType.BLIND) ? Passenger_TypeBLNDIndicator.Item1 : 0;
                    passenger.DEAFIndicator = ((prl.SSR & SSRType.DEAF) == SSRType.DEAF) ? Passenger_TypeDEAFIndicator.Item1 : 0;
                    passenger.UMIndicator = ((prl.SSR & SSRType.UM) == SSRType.UM) ? Passenger_TypeUMIndicator.Item1 : 0;
                    passenger.ID1Indicator = ((prl.SSR & SSRType.ID1) == SSRType.ID1) ? Passenger_TypeID1Indicator.Item1 : 0;
                    passenger.WCBDIndicator = ((prl.SSR & SSRType.WCBD) == SSRType.WCBD) ? Passenger_TypeWCBDIndicator.Item1 : 0;
                    passenger.WCBWIndicator = (prl.SSR & SSRType.WCBW) == SSRType.WCBW ? Passenger_TypeWCBWIndicator.Item1 : 0;
                    passenger.WCHCIndicator = (prl.SSR & SSRType.WCHC) == SSRType.WCHC ? Passenger_TypeWCHCIndicator.Item1 : 0;
                    passenger.WCHRIndicator = (prl.SSR & SSRType.WCHR) == SSRType.WCHR ? Passenger_TypeWCHRIndicator.Item1 : 0;
                    passenger.WCHSIndicator = (prl.SSR & SSRType.WCHS) == SSRType.WCHS ? Passenger_TypeWCHSIndicator.Item1 : 0;
                    passenger.WCMPIndicator = (prl.SSR & SSRType.WCMP) == SSRType.WCMP ? Passenger_TypeWCMPIndicator.Item1 : 0;
                    passenger.WCOBIndicator = (prl.SSR & SSRType.WCOB) == SSRType.WCOB ? Passenger_TypeWCOBIndicator.Item1 : 0;

                    passenger.STCRIndicatorSpecified = ((prl.SSR & SSRType.STCR) == SSRType.STCR);
                    passenger.VIPIndicatorSpecified = prl.IsVip;
                    passenger.BLNDIndicatorSpecified = (prl.SSR & SSRType.BLIND) == SSRType.BLIND;
                    passenger.DEAFIndicatorSpecified = (prl.SSR & SSRType.DEAF) == SSRType.DEAF;
                    passenger.UMIndicatorSpecified = (prl.SSR & SSRType.UM) == SSRType.UM;
                    passenger.ID1IndicatorSpecified = (prl.SSR & SSRType.ID1) == SSRType.ID1;
                    passenger.WCBDIndicatorSpecified = (prl.SSR & SSRType.WCBD) == SSRType.WCBD;
                    passenger.WCBWIndicatorSpecified = (prl.SSR & SSRType.WCBW) == SSRType.WCBW;
                    passenger.WCHCIndicatorSpecified = (prl.SSR & SSRType.WCHC) == SSRType.WCHC;
                    passenger.WCHRIndicatorSpecified = (prl.SSR & SSRType.WCHR) == SSRType.WCHR;
                    passenger.WCHSIndicatorSpecified = (prl.SSR & SSRType.WCHS) == SSRType.WCHS;
                    passenger.WCMPIndicatorSpecified = (prl.SSR & SSRType.WCMP) == SSRType.WCMP;
                    passenger.WCOBIndicatorSpecified = (prl.SSR & SSRType.WCOB) == SSRType.WCOB;

                    passenger.InfantNumber = (((prl.SSR & SSRType.INF1) == SSRType.INF1) || ((prl.SSR & SSRType.INF2) == SSRType.INF2)) ? "0" : (prl.SSR == SSRType.INF1 ? 1 : (prl.SSR == SSRType.INF2 ? 2 : 0)).ToString();
                    passenger.ChildrenNumber = (((prl.SSR & SSRType.CHD1) == SSRType.CHD1) || ((prl.SSR & SSRType.CHD2) == SSRType.CHD2)) ? "0" : (prl.SSR == SSRType.CHD1 ? 1 : (prl.SSR == SSRType.CHD2 ? 2 : 0)).ToString();

                    #endregion
                }

                #endregion

                category.Passenger = passengers.ToArray();

                #region Build Segment_Type

                Segment_Type segment;
                if (string.IsNullOrEmpty(prlFlightCabinNoGroup.Key))
                    segment = new Segment_Type()
                    {
                        ArriveAirport = string.Empty,
                        PassengersCount = string.Empty,
                        SubCabin = string.Empty,
                    };
                else
                {
                    segment = new Segment_Type();
                    segment.ArriveAirport = prlFlightCabinNoGroup.Key.Substring(0, 3);
                    segment.PassengersCount = prlFlightCabinNoGroup.Key.Substring(3, 3);
                    segment.SubCabin = prlFlightCabinNoGroup.Key.Substring(6, 1);
                }
                #endregion

                category.Segment = segment;
            }

            #endregion

            return categories.ToArray();
        }

        #endregion

    }
}
